package com.ruike.alisurface.serialport.serial;


import com.ruike.alisurface.utils.ShareKey;
import com.voodoo.lib_logcat.L;
import com.voodoo.lib_utils.SharedUtils;
import com.voodoo.serialport.util.ByteUtils;

import java.util.List;

/**
 * Author: voodoo
 * CreateDate: 2020/05/08 008 11:59 上午
 * Description: 串口指令拼接工具类
 * <p>
 * 开启通讯	startCommunication()
 * 直流电机操作指令	sjjControlMotor(电机通道号, 开关(是否转动), 速度, 步数, 是否正转)
 * 设置电流保护阈值	sjjSetProtectCurrent(通道1, 通道2, 通道3, 通道4, 通道5, 通道6)
 * 驱动板LED灯带操作	quDongLed(电路板地址, 灯光模式, 灯光通道, 是否开灯, 呼吸灯最大亮度, 呼吸灯呼吸时间)
 * 转动驱动电机出货	quDongOutGoods(货道号, 货道类型)
 * 打开电控门锁	quDongOpenElectricDoor(货柜编号, 电磁锁通电时间, 电磁锁编号)
 * 查询驱动程序版本号和驱动板批次	quDongCheckVersion(主副柜编号)
 * 查询温控程序版本号和驱动板批次	quDonfCheckWKVersion(主副柜编号)
 */
public class SerialPortInstructUtils {


    // ============================================================================================
    // ==                  👇👇👇👇             驱动板RS485通讯          👇👇👇👇
    // ==            https://www.showdoc.cc/293549481506172?page_id=1677427733030350
    // ============================================================================================

    /**
     * 驱动板普通LED灯带
     * <p>
     * 数据格式：升降机电路板地址+数据长度+操作命令数据+LED灯工作模式+LED通道号+
     * 对应通道号LED开关状态（只在开关模式下有效）+LED灯最大亮度（只在呼吸模式下有效，0-30）
     * +呼吸灯呼吸时间（只在呼吸模式下有效，0-30）+LED使能状态+前面数据和低八位。
     * <p>
     * 注：
     * （1）升降机电路板地址为485通讯地址
     * （2）数据长度为除第一位与此数据长度位之外的数据长度
     * （3）操作命令数据表示该指令的控制对象。
     * （4）LED工作模式：0-开关，1-呼吸
     * （5）LED通道号：0为LED1，1为LED2
     * （6）对应通道号LED开关状态（只在开关模式下有效）：0-关，1-开
     * （7）呼吸灯最大亮度（只在呼吸模式下有效）：取值1-30
     * （8）呼吸灯呼吸时间（只在呼吸模式下有效）：取值1-30
     * （9）LED使能状态：0-失能，1-使能
     * （10）校验位：前面数据和低八位
     * <p>
     *
     * @param pcbAddress 电路板地址 10 11 12
     * @param ledMode    灯光模式 0：开关模式  1：呼吸模式
     * @param chanl      灯光通道 0 1 2
     * @param isOpen     对应通道号LED开关状态（只在开关模式下有效）：0-关，1-开
     * @param largLight  呼吸灯最大亮度（只在呼吸模式下有效）：取值1-30
     * @param largtime   呼吸灯呼吸时间（只在呼吸模式下有效）：取值1-30
     */
    public static String quDongLed(int pcbAddress, int ledMode, int chanl, boolean isOpen, int largLight, int largtime) {
        byte[] strSerialComSend = new byte[10];
        byte strSerialChkSum_Int16 = 0;

        // 电路板地址
        switch (pcbAddress) {
            case 10:
                strSerialComSend[0] = 0x10;
                break;
            case 11:
                strSerialComSend[0] = 0x11;
                break;
            case 12:
                strSerialComSend[0] = 0x12;
                break;
            case 13:
                strSerialComSend[0] = 0x13;
                break;
            case 14:
                strSerialComSend[0] = 0x14;
                break;
        }

        // 数据长度
        strSerialComSend[1] = 0x08;

        // 开启LED灯指令标识
        strSerialComSend[2] = 0x05;

        // 工作模式
        strSerialComSend[3] = (byte) ledMode;

        // 灯光通道 0x00 0x01 0x02
        strSerialComSend[4] = (byte) chanl;

        // 对应通道号LED开关状态（只在开关模式下有效） 0-关，1-开
        strSerialComSend[5] = (byte) (isOpen ? 1 : 0);

        // 呼吸最大亮度（只在呼吸模式下有效）取值1-30
        strSerialComSend[6] = (byte) 0x1E;

        // 呼吸灯呼吸时间（只在呼吸模式下有效）取值1-30
        strSerialComSend[7] = (byte) largtime;

        // LED使能状态 0-失能，1-使能
        strSerialComSend[8] = 0x01;

        // 低八位校验和
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[9] = strSerialChkSum_Int16;

        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }

    /**
     * 驱动板出货
     * <p>
     * 数据协议格式：驱动板地址 + 数据长度 + 命令数据 + 总出货货道数量 +
     * 1货道号 + 1出货数量 + 1货道类型 +
     * 2货道号 + 2货道出货数量 + 2货道类型 +
     * 3货道号 + 3货道出货数量 + 3货道类型 +
     * 4货道号 + 4货道出货数量 + 4货道类型 +
     * 5货道号 + 5货道出货数量 + 5货道类型 +
     * 前面数据和低八位。
     * <p>
     * 示例数据：10 06 00 01 2E 01 00 46
     * 示例数据：10 09 00 02 01 01 00 02 02 00 21 暂时不支持多货道出货方法需修改本地方法
     * <p>
     * 注：
     * （1）驱动板地址为485通讯地址，主柜为0x10，副柜1位0x11，副柜2为0x12，以此类推。
     * （2）数据长度为第一位与此数据长度位之外的数据长度。
     * （3）出货指令标识
     * （4）总出货数量 为一次性选择的出货货道总数，最大值为5，也就是说一次性最多可以买五种商品。1表示一次出一种货，此时数据格式：
     * 驱动板地址+数据长度+命令数据+总出货货道数量+1货道号+1货道类型+前面数据和低八位。
     * （5）货道号
     * （6）当前货道号出货数量
     * （7）货道类型：0-弹簧货道，1-电磁锁货道，2-履带货道
     * 5、6、7 循环，多货道出货，最大为5
     *
     * @param index     货道号
     * @param indexType 货道类型 0-弹簧货道，1-电磁锁货道，2-履带 3- 推板
     */
    public static String quDongOutGoods(int index, int indexType) {
        int res = 0;
        byte[] strSerialComSend = new byte[8];
        byte strSerialChkSum_Int16 = 0;
        // 驱动板地址，如果第一块就是0x10，第二块就是0x11，依次类推
        int Hdh_num = SharedUtils.getInstance().getInt(ShareKey.IC2_SLOT_NUM, 100);
        L.i("Hdh_num  货道柜数===" + Hdh_num);
        if (index < Hdh_num) {
            res = index;
            strSerialComSend[0] = 0x10;
        } else if (index >= Hdh_num && index < Hdh_num * 2) {
            strSerialComSend[0] = 0x11;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 2 && index < Hdh_num * 3) {
            strSerialComSend[0] = 0x12;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 3 && index < Hdh_num * 4) {
            strSerialComSend[0] = 0x13;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 4 && index < Hdh_num * 5) {
            strSerialComSend[0] = 0x14;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 5 && index < Hdh_num * 6) {
            strSerialComSend[0] = 0x15;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 6 && index < Hdh_num * 7) {
            strSerialComSend[0] = 0x16;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 7 && index < Hdh_num * 8) {
            strSerialComSend[0] = 0x17;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 8 && index < Hdh_num * 9) {
            strSerialComSend[0] = 0x18;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 9 && index < Hdh_num * 10) {
            strSerialComSend[0] = 0x19;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 10) {
            L.e("连接的板子已经超出了范围...");

            return "";
        }

        strSerialComSend[1] = 0x06;

        strSerialComSend[2] = 0x00;

        // 商品种类
        strSerialComSend[3] = 0x01;

        // 货道编号
        strSerialComSend[4] = (byte) res;

        // 货道数量
        strSerialComSend[5] = 0x01;

        // 货道类型 0-弹簧货道，1-电磁锁货道，2-蛇形货道 3 推板货道
        strSerialComSend[6] = (byte) indexType;
        L.i("货道类型 === " + (indexType == 0 ? "弹簧货道" : indexType == 1 ? "电磁锁货道"
                : indexType == 2 ? "履带货道" : "推板货道"));
        // 低八位校验和
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        // 校验位
        strSerialComSend[7] = strSerialChkSum_Int16;
        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }

    public static String quDongOutGoods(int index, int indexType, int turnNumber) {
        int res = 0;
        byte[] strSerialComSend = new byte[8];
        byte strSerialChkSum_Int16 = 0;
        // 驱动板地址，如果第一块就是0x10，第二块就是0x11，依次类推
        int Hdh_num = SharedUtils.getInstance().getInt(ShareKey.IC2_SLOT_NUM, 100);
        L.i("Hdh_num  货道柜数===" + Hdh_num);
        if (index < Hdh_num) {
            res = index;
            strSerialComSend[0] = 0x10;
        } else if (index >= Hdh_num && index < Hdh_num * 2) {
            strSerialComSend[0] = 0x11;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 2 && index < Hdh_num * 3) {
            strSerialComSend[0] = 0x12;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 3 && index < Hdh_num * 4) {
            strSerialComSend[0] = 0x13;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 4 && index < Hdh_num * 5) {
            strSerialComSend[0] = 0x14;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 5 && index < Hdh_num * 6) {
            strSerialComSend[0] = 0x15;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 6 && index < Hdh_num * 7) {
            strSerialComSend[0] = 0x16;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 7 && index < Hdh_num * 8) {
            strSerialComSend[0] = 0x17;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 8 && index < Hdh_num * 9) {
            strSerialComSend[0] = 0x18;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 9 && index < Hdh_num * 10) {
            strSerialComSend[0] = 0x19;
            res = index % Hdh_num;
        } else if (index >= Hdh_num * 10) {
            L.e("连接的板子已经超出了范围...");
            return "";
        }

        strSerialComSend[1] = 0x06;

        // 出货指令标识
        strSerialComSend[2] = 0x00;

        // 出货货道数量
        strSerialComSend[3] = 0x01;

        // ==================================

        // 出货货道编号
        strSerialComSend[4] = (byte) res;

        // 该货道号出货数量
        strSerialComSend[5] = (byte) turnNumber;

        // 货道类型 0-弹簧货道，1-电磁锁货道，2-履带货道
        strSerialComSend[6] = (byte) indexType;

        L.i(new StringBuffer().append(index).append("货道出货数量：").append(turnNumber)
                .append(" 货道类型：").append(indexType == 0 ? "弹簧货道" : indexType == 1 ?
                        "电磁锁货道" : indexType == 2 ? "履带货道" : "推板货道"));
        // ==================================
        // 低八位校验和
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        // 校验位
        strSerialComSend[7] = strSerialChkSum_Int16;

        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }

    /**
     * 驱动板开启电控锁
     *
     * @param boxno    货柜编号 0是主柜 现在只能是0到4，1是第一辅柜0x11，2是第二辅柜0x12 ...
     * @param ElecNum  电磁锁编号 0表示1通道，1表示2通道
     * @param ElecOnTi 电磁锁通电时间 取值3-50，对应0.3s-5s
     * @return
     */
    public static String quDongOpenElectricDoor(int boxno, int ElecOnTi, int ElecNum) {
        byte[] strSerialComSend = new byte[6];
        byte strSerialChkSum_Int16 = 0;

        // 485设备地址 主柜为0x10，副柜1位0x11，副柜2为0x12 ...
        switch (boxno) {
            case 0:
                strSerialComSend[0] = 0x10;
                break;
            case 1:
                strSerialComSend[0] = 0x11;
                break;
            case 2:
                strSerialComSend[0] = 0x12;
                break;
            case 3:
                strSerialComSend[0] = 0x13;
                break;
            case 4:
                strSerialComSend[0] = 0x14;
                break;
        }

        // 数据长度
        strSerialComSend[1] = 0x04;

        // 开启电控锁指令标识
        strSerialComSend[2] = 0x03;

        // 00表示通道1锁 01表示通道2锁
        strSerialComSend[3] = (byte) ElecNum;

        // 电控锁开启时间
        strSerialComSend[4] = (byte) ElecOnTi;

        // 低八位校验和
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[5] = (byte) (strSerialChkSum_Int16 >> 0);

        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }


    /**
     * 温控
     *
     * @param model 工作模式 0：制冷  1：制热  >1：关闭
     * @return 拼接完的指令字符串
     * 020001000A3C0201010000FF01
     */
    public static String temperatureControl(int model) {
        byte strSerialChkSum_Int16 = 0;
        int index = 0;
        byte[] strSerialComSend = new byte[16];
        strSerialComSend[index] = 0x23; // 站号 20+
        strSerialComSend[++index] = 0x0E; // 数据长度
        strSerialComSend[++index] = 0x02; // 0x02自动模式 0x01手动模式 0x03 请求发送数据
        strSerialComSend[++index] = (byte) (model == 0 ? 0x00 : model == 1 ? 0x01 : 0x03); // 00：制冷最低温度0° 01：制热最高温度50°  02：恒温（暂时不支持）  03：停止工作
        strSerialComSend[++index] = 0x01; // 温度正负标志 0x01正， 0x02负
        strSerialComSend[++index] = 0x05; // 温度
        strSerialComSend[++index] = 0x05; // 制冷/加热除霜时间 休息时间、停机时间
        strSerialComSend[++index] = 0x3C; // 总循环时间（可改，建议60min）
        strSerialComSend[++index] = 0x02; // 温度偏差 （启动温度，停止温度）
        strSerialComSend[++index] = 0x01; // 0x00臭氧启动 0x01臭氧停止//工作方式：工作30分钟，停机2小时(固定值)
        strSerialComSend[++index] = 0x00; // 0x00玻璃加热启动 0x01玻璃加热停止
        strSerialComSend[++index] = 0x0F; // 0x00玻璃加热工作时间 （2019.3.7修改） 最大时间180MIN
        strSerialComSend[++index] = 0x0F; // 0x00玻璃加热停机时间（2019.3.7修改） 最大时间180MIN
        strSerialComSend[++index] = 0x01; // 0x00加湿器启动 0x01加湿器停止 // 固定数值0XFF
        strSerialComSend[++index] = 0x01; // 询问是否发送成功 固定值
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[++index] = strSerialChkSum_Int16; // 校验位
        return ByteUtils.byteArrToHex(strSerialComSend);
    }

    /**
     * 温控
     *
     * @param resultBytes Mqtt传入的byte数组
     * @return 拼接完的指令字符串
     */
    public static String temperatureControl(byte[] resultBytes) {
        byte strSerialChkSum_Int16 = 0;
        int index = 0;
        byte[] strSerialComSend = new byte[16];
        strSerialComSend[index] = 0x23; // 站号 20+
        strSerialComSend[++index] = 0x0E; // 数据长度

        if (resultBytes == null || resultBytes.length < 13) {
            return "";
        } else {
            for (int i = 0; i < 13; i++) {
                strSerialComSend[++index] = resultBytes[i]; // 循环将返回的值放置到命令中
            }
//            resultBytes[0]; // 0x02自动模式 0x01手动模式 0x03 请求发送数据
//            resultBytes[1]; // 00：制冷最低温度0° 01：制热最高温度50°  02：恒温（暂时不支持）  03：停止工作
//            resultBytes[2]; // 温度正负标志 0x01正， 0x02负
//            resultBytes[3]; // 温度
//            resultBytes[4]; // 制冷/加热除霜时间 休息时间、停机时间
//            resultBytes[5]; // 总循环时间（可改，建议60min）
//            resultBytes[6]; // 温度偏差 （启动温度，停止温度）
//            resultBytes[7]; // 0x00臭氧启动 0x01臭氧停止//工作方式：工作30分钟，停机2小时(固定值)
//            resultBytes[8]; // 0x00玻璃加热启动 0x01玻璃加热停止
//            resultBytes[9]; // 0x00玻璃加热工作时间 （2019.3.7修改） 最大时间180MIN
//            resultBytes[10]; // 0x00玻璃加热停机时间（2019.3.7修改） 最大时间180MIN
//            resultBytes[11]; // 0x00加湿器启动 0x01加湿器停止 // 固定数值0XFF
//            resultBytes[12]; // 询问是否发送成功 固定值
        }

        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[++index] = strSerialChkSum_Int16; // 校验位
        return ByteUtils.byteArrToHex(strSerialComSend);
    }

    /**
     * 温控
     *
     * @param model 工作模式 0：制冷  1：制热  >1：关闭
     * @return 拼接完的指令字符串
     * 020001000A3C0201010000FF01
     */
    public static String temperatureControl(int model, int temperature) {
        byte strSerialChkSum_Int16 = 0;
        int index = 0;
        byte[] strSerialComSend = new byte[16];
        strSerialComSend[index] = 0x23; // 站号 20+
        strSerialComSend[++index] = 0x0E; // 数据长度
        strSerialComSend[++index] = 0x02; // 0x02自动模式 0x01手动模式 0x03 请求发送数据
        strSerialComSend[++index] = (byte) (model == 0 ? 0x00 : model == 1 ? 0x01 : 0x03); // 00：制冷最低温度0° 01：制热最高温度50°  02：恒温（暂时不支持）  03：停止工作
        strSerialComSend[++index] = 0x01; // 温度正负标志 0x01正， 0x02负
        strSerialComSend[++index] = (byte) temperature; // 温度
        strSerialComSend[++index] = 0x05; // 制冷/加热除霜时间 休息时间、停机时间
        strSerialComSend[++index] = 0x3C; // 总循环时间（可改，建议60min）
        strSerialComSend[++index] = 0x02; // 温度偏差 （启动温度，停止温度）
        strSerialComSend[++index] = 0x00; // 0x00臭氧启动 0x01臭氧停止//工作方式：工作30分钟，停机2小时(固定值)
        strSerialComSend[++index] = 0x00; // 0x00玻璃加热启动 0x01玻璃加热停止
        strSerialComSend[++index] = 0x0F; // 0x00玻璃加热工作时间 （2019.3.7修改） 最大时间180MIN
        strSerialComSend[++index] = 0x0F; // 0x00玻璃加热停机时间（2019.3.7修改） 最大时间180MIN
        strSerialComSend[++index] = 0x01; // 0x00加湿器启动 0x01加湿器停止 // 固定数值0XFF
        strSerialComSend[++index] = 0x01; // 询问是否发送成功 固定值
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[++index] = strSerialChkSum_Int16; // 校验位
        return ByteUtils.byteArrToHex(strSerialComSend);
    }

    /**
     * 温控
     *
     * @param model 工作模式 0：制冷  1：制热  >1：关闭
     * @param mark  温度正负标志 0x01正， 0x02负
     * @return 拼接完的指令字符串
     * 020001000A3C0201010000FF01
     */
    public static String temperatureControl(int model, int mark, int temperature) {
        byte strSerialChkSum_Int16 = 0;
        int index = 0;
        byte[] strSerialComSend = new byte[16];
        strSerialComSend[index] = 0x23; // 站号 20+
        strSerialComSend[++index] = 0x0E; // 数据长度
        strSerialComSend[++index] = 0x02; // 0x02自动模式 0x01手动模式 0x03 请求发送数据
        strSerialComSend[++index] = (byte) (model == 0 ? 0x00 : model == 1 ? 0x01 : 0x03); // 00：制冷最低温度0° 01：制热最高温度50°  02：恒温（暂时不支持）  03：停止工作
        strSerialComSend[++index] =(byte) mark; // 温度正负标志 0x01正， 0x02负
        strSerialComSend[++index] = (byte) temperature; // 温度
        strSerialComSend[++index] = 0x05; // 制冷/加热除霜时间 休息时间、停机时间
        strSerialComSend[++index] = 0x3C; // 总循环时间（可改，建议60min）
        strSerialComSend[++index] = 0x02; // 温度偏差 （启动温度，停止温度）
        strSerialComSend[++index] = 0x00; // 0x00臭氧启动 0x01臭氧停止//工作方式：工作30分钟，停机2小时(固定值)
        strSerialComSend[++index] = 0x00; // 0x00玻璃加热启动 0x01玻璃加热停止
        strSerialComSend[++index] = 0x0F; // 0x00玻璃加热工作时间 （2019.3.7修改） 最大时间180MIN
        strSerialComSend[++index] = 0x0F; // 0x00玻璃加热停机时间（2019.3.7修改） 最大时间180MIN
        strSerialComSend[++index] = 0x01; // 0x00加湿器启动 0x01加湿器停止 // 固定数值0XFF
        strSerialComSend[++index] = 0x01; // 询问是否发送成功 固定值
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[++index] = strSerialChkSum_Int16; // 校验位
        return ByteUtils.byteArrToHex(strSerialComSend);
    }


    /**
     * 查询驱动程序版本号和驱动板批次
     *
     * @param cabinet 主副柜
     */
    public static String checkQuDongVersion(int cabinet) {

        byte[] strSerialComSend = new byte[5];
        byte strSerialChkSum_Int16 = 0;

        switch (cabinet) {
            case 10:
                strSerialComSend[0] = 0x10;
                break;
            case 11:
                strSerialComSend[0] = 0x11;
                break;
            case 12:
                strSerialComSend[0] = 0x12;
                break;
            case 13:
                strSerialComSend[0] = 0x13;
                break;
        }

        strSerialComSend[1] = 0x03;
        strSerialComSend[2] = 0x1C;
        strSerialComSend[3] = (byte) (cabinet - 10);
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[4] = strSerialChkSum_Int16;

        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }

    /**
     * 查询温控程序版本号和驱动板批次和 温控值  继电器及运行类型
     * 23 03 03 06 2F
     * 23 03 03 03 2C
     * <p>
     * 23 03 03 04 2D
     * 23 03 03 05 2E
     *
     * @param cabinet 类型    06       03      04       05
     */
    public static String checkWenKongVersion(int cabinet) {

        byte[] strSerialComSend = new byte[5];
        byte strSerialChkSum_Int16 = 0;

        strSerialComSend[0] = 0x23;
        strSerialComSend[1] = 0x03;
        strSerialComSend[2] = 0x03;
        strSerialComSend[3] = (byte) cabinet;
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[4] = strSerialChkSum_Int16;
        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }


    /**
     * 驱动板普通LED灯带
     * <p>
     * 数据格式：升降机电路板地址+数据长度+操作命令数据+LED灯工作模式+LED通道号+
     * 对应通道号LED开关状态（只在开关模式下有效）+LED灯最大亮度（只在呼吸模式下有效，0-30）
     * +呼吸灯呼吸时间（只在呼吸模式下有效，0-30）+LED使能状态+前面数据和低八位。
     * <p>
     * 注：
     * （1）升降机电路板地址为485通讯地址
     * （2）数据长度为除第一位与此数据长度位之外的数据长度
     * （3）操作命令数据表示该指令的控制对象。
     * （4）LED工作模式：0-开关，1-呼吸
     * （5）LED通道号：0为LED1，1为LED2
     * （6）对应通道号LED开关状态（只在开关模式下有效）：0-关，1-开
     * （7）呼吸灯最大亮度（只在呼吸模式下有效）：取值1-30
     * （8）呼吸灯呼吸时间（只在呼吸模式下有效）：取值1-30
     * （9）LED使能状态：0-失能，1-使能
     * （10）校验位：前面数据和低八位
     * <p>
     *
     * @param pcbAddress 电路板地址 10 11 12
     * @param ledMode    灯光模式 0：开关模式  1：呼吸模式
     * @param ledChannel 灯光通道 0 1 2
     * @param isOpen     对应通道号LED开关状态（只在开关模式下有效）：0-关，1-开
     * @param maxLight   呼吸灯最大亮度（只在呼吸模式下有效）：取值1-30
     * @param ledTime    呼吸灯呼吸时间（只在呼吸模式下有效）：取值1-30
     */
    public static String ledLight(int pcbAddress, int ledMode, int ledChannel, boolean isOpen, int maxLight, int ledTime) {
        byte[] strSerialComSend = new byte[10];
        byte strSerialChkSum_Int16 = 0;

        // 电路板地址
        switch (pcbAddress) {
            case 10:
                strSerialComSend[0] = 0x10;
                break;
            case 11:
                strSerialComSend[0] = 0x11;
                break;
            case 12:
                strSerialComSend[0] = 0x12;
                break;
            case 13:
                strSerialComSend[0] = 0x13;
                break;
            case 14:
                strSerialComSend[0] = 0x14;
                break;
        }

        // 数据长度
        strSerialComSend[1] = 0x08;

        // 开启LED灯指令标识
        strSerialComSend[2] = 0x05;

        // 工作模式
        strSerialComSend[3] = (byte) ledMode;

        // 灯光通道 0x00 0x01 0x02
        strSerialComSend[4] = (byte) ledChannel;

        // 对应通道号LED开关状态（只在开关模式下有效） 0-关，1-开
        strSerialComSend[5] = (byte) (isOpen ? 1 : 0);

        // 呼吸最大亮度（只在呼吸模式下有效）取值1-30
        strSerialComSend[6] = (byte) maxLight;

        // 呼吸灯呼吸时间（只在呼吸模式下有效）取值1-30
        strSerialComSend[7] = (byte) ledTime;

        // LED使能状态 0-失能，1-使能
        strSerialComSend[8] = 0x01;

        // 低八位校验和
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[9] = strSerialChkSum_Int16;

        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }

    //湿度
    public static String checkhumidity() {
        byte[] strSerialComSend = new byte[8];
        strSerialComSend[0] = 0x01;
        strSerialComSend[1] = 0x03;
        strSerialComSend[2] = 0x00;
        strSerialComSend[3] = 0x00;
        strSerialComSend[4] = 0x00;
        strSerialComSend[5] = 0x02;
        strSerialComSend[6] = (byte) 0xC4;
        strSerialComSend[7] = 0x0B;
        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }


    /**
     * 紫外灯启停
     * 是否开灯
     * 例如  23 04 10 01 00 38
     *
     * @param isLights true  开灯  false  关灯
     *                 <p>
     *                 开关灯指令返回:
     *                 数据方向：温控板到安卓板
     *                 数据格式：十六进制
     *                 例如 23 03 11 00 37
     */
    public static String UV_lamp_start_and_stop(boolean isLights) {
        byte[] strSerialComSend = new byte[6];
        byte strSerialChkSum_Int16 = 0;
        strSerialComSend[0] = 0x23;
        // 数据长度
        strSerialComSend[1] = 0x04;
        // 开启电控锁指令标识
        strSerialComSend[2] = 0x10;
        // 00表示通道1锁 01表示通道2锁
        strSerialComSend[3] = (byte) (isLights ? 1 : 0);
        // 电控锁开启时间 500
        strSerialComSend[4] = (byte) 00;
        // 低八位校验和
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[5] = strSerialChkSum_Int16;
        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }

    /**
     * 设置每一层 电机最大转动时间
     *
     * @param address          驱动板地址
     * @param aisle            层数
     * @param rotationTimeList 各个电机的转动时间
     * @return 10 04 21 EE 01 24  返回值
     */
    public static String set_Aisle_rotation_time(int address, int aisle, List<Integer> rotationTimeList) {
        byte[] strSerialComSend = new byte[16];
        byte strSerialChkSum_Int16 = 0;
        // 电路板地址
        switch (address) {
            case 10:
                strSerialComSend[0] = 0x10;
                break;
            case 11:
                strSerialComSend[0] = 0x11;
                break;
            case 12:
                strSerialComSend[0] = 0x12;
                break;
            case 13:
                strSerialComSend[0] = 0x13;
                break;
            case 14:
                strSerialComSend[0] = 0x14;
                break;
        }
        strSerialComSend[1] = 0x0E;
        strSerialComSend[2] = 0x20;
        strSerialComSend[3] = (byte) 0XEE;
        strSerialComSend[4] = (byte) aisle;
        int byteLength = 5;
        for (Integer it : rotationTimeList) {
            strSerialComSend[byteLength] = it.byteValue();
            byteLength++;
        }
        // 低八位校验和
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[16 - 1] = strSerialChkSum_Int16;
        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }

    static int countId;

    /**
     * 保存  安卓完成设置电机最大电机转动时间（0x22）
     * 10 04 22 EE 01 25
     *
     * @param address
     * @return 10 04 23 01 01 39  设置成功的返回值
     */
    public static String set_save_all_rotation_time(int address) {
        byte[] strSerialComSend = new byte[6];
        byte strSerialChkSum_Int16 = 0;
        switch (address) {
            case 10:
                strSerialComSend[0] = 0x10;
                break;
            case 11:
                strSerialComSend[0] = 0x11;
                break;
            case 12:
                strSerialComSend[0] = 0x12;
                break;
            case 13:
                strSerialComSend[0] = 0x13;
                break;
            case 14:
                strSerialComSend[0] = 0x14;
                break;
        }
        strSerialComSend[1] = 0x04;
        strSerialComSend[2] = 0x22;
        countId++;
        if (countId > 255) {
            countId = 0;
        }
        strSerialComSend[3] = (byte) countId;
        strSerialComSend[4] = (byte) 0x01;
        // 低八位校验和
        for (byte tempByte : strSerialComSend) {
            strSerialChkSum_Int16 += (tempByte & 0xff);
        }
        strSerialComSend[5] = strSerialChkSum_Int16;
        return ByteUtils.byteArrToHex(strSerialComSend, strSerialComSend.length);
    }
}
